package com.hulk.boot.service.interceptor;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;

import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.hulk.boot.common.component.Response;
import com.hulk.boot.common.constant.enums.BussErrCode;
import com.hulk.boot.common.exception.BaseException;
import com.hulk.boot.common.exception.BaseRteException;
import com.hulk.boot.common.tool.ValidatorTool;

import lombok.extern.slf4j.Slf4j;


/**
 * 定义异常处理的切面
 * 
 * @author  CMT
 * 
 */
@Component
@Order(4)
@Aspect
@Slf4j
public class AfterThrowingAdvice {
	/**
	 * 添加业务逻辑方法切入点
	 */
	// 这个表达式现在配置错误， 应该只拦截 service 下面的类，在service子包的类就不拦截了 execution(* com.hulk.boot.service..*.*(..)  //TODO
	//@Pointcut("execution(public * com.hulk.boot.service.*.*(..))")
	@Pointcut("execution(* com.hulk.boot.service.*.*(..))")
	public void allService() {
		//http://edu.51cto.com/lesson/id-36989.html
	}
	
	
	@Around(value = "allService()")
	public Object transferException(ProceedingJoinPoint pjp) {
		
		MethodSignature signature =(MethodSignature) pjp.getSignature();
		Method method = signature.getMethod();
		Class<?> methodReturnType = method.getReturnType();
		Object result = null;
		String errorCode = null;
		String errorMsg = null;
		if (methodReturnType.isAssignableFrom(Response.class)) {// 如果返回类型不是  Response不进行异常拦截处理,通过 dubbo或者http协议，client层自己捕获
			// 传入参数 validation验证
			// spring-boot 默认hibernate-validator 版本 和dubbo的版本相差太大, 所以采用拦截器实现validation以兼容spring-boot，dubbo自带的validation弃用
			for (Object obj : pjp.getArgs()) {
				errorMsg =	ValidatorTool.validateBean(obj);
				if(!Strings.isNullOrEmpty(errorMsg)){
					errorCode = BussErrCode.E_P1.getErrCode();
					result = new Response<Object>(errorCode, errorMsg);
					log.error("request paramater  validation failed.............. method:{},params:{},errorCode:{},errorMsg:{}",
						new Object[] { method.toGenericString(), pjp.getArgs(), errorCode,errorMsg });
					return result ;
				}
			}
			
			try {
				result = pjp.proceed();
			} catch (Throwable e) {
				log.error("transferException  occurred.............. method:{},params:{},cause:{}",
						new Object[] { method.toGenericString(), pjp.getArgs(), Throwables.getStackTraceAsString(e) });
				if (e instanceof BaseException) {
					errorCode = ((BaseException) e).getErrorCode();
					errorMsg = ((BaseException) e).getErrorMessage();
				} else if (e instanceof BaseRteException) {
					errorCode = ((BaseRteException) e).getErrorCode();
					errorMsg = ((BaseRteException) e).getErrorMessage();
				} else if (e instanceof DataIntegrityViolationException) {
					if (e.toString().contains("ORA-00001")) {
						errorCode = BussErrCode.E_P5.getErrCode();
						errorMsg = BussErrCode.E_P5.getErrDesc();
					} else {
						errorCode = BussErrCode.E_P6.getErrCode();
						errorMsg = BussErrCode.E_P6.getErrDesc();
					}
				} else if (e instanceof CannotAcquireLockException) {
					errorCode = BussErrCode.E_P7.getErrCode();
					errorMsg = BussErrCode.E_P7.getErrDesc();
				} else {
					errorCode = BussErrCode.E_PP.getErrCode();
					errorMsg = BussErrCode.E_PP.getErrDesc();
				}
				log.error("transferException  occurred..............method:{},params:{},Response:{},cause:{}",
						new Object[] { method.toGenericString(), pjp.getArgs(), result,
								Throwables.getStackTraceAsString(e) });
				result = new Response<Object>(errorCode, errorMsg);
				return result;
			}
			
			// 返回参数validation验证, 可以不验证
			@SuppressWarnings("unchecked")
			Response<Object> resultResponse =(Response<Object>)result;
			errorMsg=  ValidatorTool.validateBean(resultResponse.getResult());
		    if(!Strings.isNullOrEmpty(errorMsg)){
				errorCode = BussErrCode.E_P2.getErrCode();
				result = new Response<Object>(errorCode, errorMsg);
				log.error("respone paramater  validation failed.............. method:{},params:{},errorCode:{},errorMsg:{}",
						new Object[] { method.toGenericString(), pjp.getArgs(), errorCode,errorMsg });
				return result;
		    }
			return result;
			
		} else { // 如果返回类型不是  Response不进行异常处理,通过 dubbo或者http协议，client层自己捕获
			try {
				//不需要validation验证 client自行验证
				result = pjp.proceed();
			} catch (Throwable e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
			return result;
		}
	
	}
	
	
	
	// 因为 异常通知没有返回值  即使返回参数不为void 也没用， 所以这种方式不能使用
    /*
	@AfterThrowing( value = "allService()", throwing = "e")
	public void doException(JoinPoint jp, Exception e) {
		Response<Object> result = null;
		try {
			org.aspectj.lang.Signature signature = jp.getSignature();
			String name = signature.getName();
			Method method = ((MethodSignature) signature).getMethod();
			
			if (e != null) {
				log.error("transferException  occurred..............name:{}, method:{},params:{},cause:{}",
						new Object[] { name, method.toGenericString(), jp.getArgs(), Throwables.getStackTraceAsString(e) });
				// if (methodReturnType.isAssignableFrom(Response.class)) {
				String errorCode = null;
				String errorMsg = null;
				if (e instanceof BaseException) {
					errorCode = ((BaseException) e).getErrorCode();
					errorMsg = ((BaseException) e).getErrorMessage();
				} else if (e instanceof BaseRteException) {
					errorCode = ((BaseRteException) e).getErrorCode();
					errorMsg = ((BaseRteException) e).getErrorMessage();
				} else if (e instanceof DataIntegrityViolationException) {
					if (e.toString().contains("ORA-00001")) {
						errorCode = BussErrCode.E_P5.getErrCode();
						errorMsg = BussErrCode.E_P5.getErrDesc();
					} else {
						errorCode = BussErrCode.E_P6.getErrCode();
						errorMsg = BussErrCode.E_P6.getErrDesc();
					}
				} else if (e instanceof CannotAcquireLockException) {
					errorCode = BussErrCode.E_P7.getErrCode();
					errorMsg = BussErrCode.E_P7.getErrDesc();
				} else {
					errorCode = BussErrCode.E_PP.getErrCode();
					errorMsg = BussErrCode.E_PP.getErrDesc();
				}
				result = new Response<Object>(errorCode, errorMsg);
				log.error("transferException  occurred..............name:{},method:{},params:{},Response:{},cause:{}",
						new Object[] { name, method.toGenericString(), jp.getArgs(), result,
								Throwables.getStackTraceAsString(e) });
			}
		} catch (Exception e1) {
			  String	errorCode = BussErrCode.E_PP.getErrCode();
			    String	errorMsg =  BussErrCode.E_PP.getErrDesc();
				result = new Response<Object>(errorCode, errorMsg);
		}
		
	}
	*/
}
